package com.lbkj.wsc;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.ServiceLoader;

public class WSC {
    static WSCInterceptor WSC_INTERCEPTOR;
    static {
        ServiceLoader<WSCInterceptor> loader = ServiceLoader.load(WSCInterceptor.class);
        for (WSCInterceptor wscInterceptor : loader) {
            WSC_INTERCEPTOR = wscInterceptor;
            break;
        }
    }

    public static WSCResult invoke(String url, String xmlPath, Object... args) {
        String xmlF = null;
        // 1. 读取配置文件
        try (InputStream is = WSC.class.getResourceAsStream(xmlPath)) {
            xmlF = IOUtils.toString(is, StandardCharsets.UTF_8);
        } catch (IOException e) {
            throw new WSCException("读取xml失败", e);
        }
        if (xmlF == null) {
            throw new WSCException("xml数据为空");
        }
        // 2. 格式化
        String xml;
        if(args == null) {
            xml = xmlF;
        } else {
            xml = String.format(xmlF, args);
        }
        final String retStr = _invoke(url, xml);
        if(WSC_INTERCEPTOR != null) {
            WSC_INTERCEPTOR.apply(xml, retStr);
        }
        final WSCResult WSCResult = parseRetStr(retStr);
        return WSCResult;
    }

    private static String _invoke(String url, String xml) {
        final HttpPost httpPost = new HttpPost(url);
        StringEntity data = new StringEntity(xml, StandardCharsets.UTF_8);
        httpPost.setEntity(data);
        httpPost.setHeader("Content-Type", "text/xml; charset=utf-8");
        httpPost.setHeader("SOAPAction", "");
        try (CloseableHttpClient httpClient = HttpClients.createDefault();) {
            final CloseableHttpResponse response = httpClient.execute(httpPost);
            HttpEntity httpEntity = response.getEntity();
            if (httpEntity != null) {
                String retStr = EntityUtils.toString(httpEntity, "UTF-8");
                return retStr;
            }
        } catch (Exception e) {
            throw new WSCException("调用服务失败", e);
        }
        return null;
    }

    private static WSCResult parseRetStr(String retStr) {
        Document document;
        try {
            document = DocumentHelper.parseText(retStr);
        } catch (DocumentException e) {
            throw new WSCException("响应结果格式错误", e);
        }
        // body
        final Element bodyEl = document.getRootElement().element("Body");
        if(bodyEl == null) {
            throw new WSCException("返回为空");
        }
        // fault
        final Element fault = bodyEl.element("Fault");
        if(fault != null) {
            String faultstring = fault.element("faultstring").getText();
            throw new WSCException(faultstring);
        }
        // response
        WSCResult wscResult = new WSCResult();
        final List<Element> responseEls = bodyEl.elements();
        if(responseEls.isEmpty()) {
            return wscResult;
        }
        Element responseEl = responseEls.get(0);
        // result
        final List<Element> resultEls = responseEl.elements();
        if(resultEls.isEmpty()) {
            wscResult.setData(responseEl.getText());
            return wscResult;
        }
        Element resultEl = resultEls.get(0);
        final List<Element> elements = resultEl.elements();
        if(elements.isEmpty()) {
            wscResult.setData(resultEl.getText());
        } else {
            wscResult.setData(resultEl.asXML());
        }
        return wscResult;
    }
}
